#include <accent/algorithms/take.hpp>
#include <type_traits>
#include "test_base.hpp"

TEST(TakeBidi, takeZero_isEmpty)
{
	ivec v = { 1, 2, 3 };
	auto r = take(0, all_b(v));
	ASSERT_TRUE(r.empty());
}

TEST(TakeBidi, takeOne_isNotEmpty)
{
	ivec v = { 1, 2, 3 };
	auto r = take(1, all_b(v));
	ASSERT_FALSE(r.empty());
}

TEST(TakeBidi, takeOne_frontIsFirst)
{
	ivec v = { 1, 2, 3 };
	auto r = take(1, all_b(v));
	ASSERT_EQ(1, r.front());
}

TEST(TakeBidi, takeOne_popFront_isEmpty)
{
	ivec v = { 1, 2, 3 };
	auto r = take(1, all_b(v));
	r.pop_front();
	ASSERT_TRUE(r.empty());
}

TEST(TakeBidi, takeTwo_popFront_isNotEmpty)
{
	ivec v = { 1, 2, 3 };
	auto r = take(2, all_b(v));
	r.pop_front();
	ASSERT_FALSE(r.empty());
}

TEST(TakeBidi, takeTwo_popFront_frontIsSecond)
{
	ivec v = { 1, 2, 3 };
	auto r = take(2, all_b(v));
	r.pop_front();
	ASSERT_EQ(2, r.front());
}

TEST(TakeBidi, takeTwoFromOne_popFront_isEmpty)
{
  ivec v = { 1 };
  auto r = take(2, all_b(v));
  r.pop_front();
  ASSERT_TRUE(r.empty());
}

TEST(TakeBidi, limitedPosition_isInvalid) {
  ivec v = { 1, 2, 3 };
  auto r = take(2, all_b(v));
  r.pop_front();
  r.pop_front();
  ASSERT_TRUE(!r.front_position());
}

TEST(TakeBidi, emptiedPosition_isInvalid) {
  ivec v = { 1, 2 };
  auto r = take(3, all_b(v));
  r.pop_front();
  r.pop_front();
  ASSERT_TRUE(!r.front_position());
}

TEST(TakeBidi, from_middlePosition_restoredCorrectly) {
  ivec v = { 1, 2, 3 };
  auto r = take(2, all_b(v)), s = r;
  s.pop_front();
  r = r.from(s.front_position());
  ASSERT_FALSE(r.empty());
  ASSERT_EQ(2, r.front());
}

TEST(TakeBidi, from_frontPosition_restoredCorrectly) {
  ivec v = { 1, 2, 3 };
  auto r = take(2, all_b(v)), s = r;
  r = r.from(s.front_position());
  ASSERT_FALSE(r.empty());
  ASSERT_EQ(1, r.front());
}

TEST(TakeBidi, until_middlePosition_restoredCorrectly) {
  ivec v = { 1, 2, 3 };
  auto r = take(2, all_b(v)), s = r;
  s.pop_front();
  r = r.until(s.front_position());
  ASSERT_FALSE(r.empty());
  ASSERT_EQ(1, r.front());
  r.pop_front();
  ASSERT_TRUE(r.empty());
}

TEST(TakeBidi, until_frontPosition_restoredCorrectly) {
  ivec v = { 1, 2, 3 };
  auto r = take(2, all_b(v)), s = r;
  r = r.until(s.front_position());
  ASSERT_TRUE(r.empty());
}

TEST(Take, takeZero_isEmpty)
{
	ivec v = { 1, 2, 3 };
	auto r = take(0, all(v));
	ASSERT_TRUE(r.empty());

	static_assert(std::is_same<decltype(r), decltype(all(v))>::value,
	  "random access take does not return same type");
}

TEST(Take, takeOne_isNotEmpty)
{
	ivec v = { 1, 2, 3 };
	auto r = take(1, all(v));
	ASSERT_FALSE(r.empty());
}

TEST(Take, takeOne_frontIsFirst)
{
	ivec v = { 1, 2, 3 };
	auto r = take(1, all(v));
	ASSERT_EQ(1, r.front());
}

TEST(Take, takeOne_popFront_isEmpty)
{
	ivec v = { 1, 2, 3 };
	auto r = take(1, all(v));
	r.pop_front();
	ASSERT_TRUE(r.empty());
}

TEST(Take, takeTwo_popFront_isNotEmpty)
{
	ivec v = { 1, 2, 3 };
	auto r = take(2, all(v));
	r.pop_front();
	ASSERT_FALSE(r.empty());
}

TEST(Take, takeTwo_popFront_frontIsSecond)
{
	ivec v = { 1, 2, 3 };
	auto r = take(2, all(v));
	r.pop_front();
	ASSERT_EQ(2, r.front());
}

TEST(Take, takeTwoFromOne_popFront_isEmpty)
{
  ivec v = { 1 };
  auto r = take(2, all(v));
  r.pop_front();
  ASSERT_TRUE(r.empty());
}
